#include "web_server.h"
#include "../pagefile/pagefile.h"
#include "../tool/md5.h"
//#include "web_page.h"
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp> 
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/typeof/typeof.hpp> 
#include <boost/foreach.hpp>  
#include <string>
#include <iostream>  
#include <sstream> 

using namespace boost::property_tree;

const char* web_uri = "/my_home";
const char *web_get_uri = "/getstate/query";
const char *web_del_uri = "/delete";
const char *web_add_uri = "/add";
const char *web_add_login = "/login";
const char * web_page_dir = "/usr1/smart_socket";

const char * dev_callback_url = "/deviceDataChanged";


const char *web_key_devid = "devid";
const char *web_key_hid = "hid";
const char *web_key_pageNo = "pageNo";
const char *web_key_type = "type";


const char* port_option = "ports";
const char* aliases_option ="aliases";
web_server::web_server(int port)
{
    _port = port;
    _phttpd = NULL;
    _is_start = false;
}

web_server::~web_server()
{
    if (_phttpd != NULL)
        delete _phttpd;
}

int web_server::init(int argc,char* argv[])
{
    _phttpd = new web_httpd((http_event*)this);
    if (_phttpd == NULL)
        return -1;

   
    if (_phttpd->init(0, argv))
        return -1;
    
    _phttpd->set_option("ssl_cert", "shttpd.pem");

    printf("port:%d\n", _port);
    std::string strport = boost::lexical_cast<std::string>(_port);//普通端口
    strport += std::string(",") + boost::lexical_cast<std::string>(_port+1) + std::string("s");//ssl端口
    //if (_phttpd->set_option(port_option, strport.c_str()))
     //   return -1;
    _phttpd->set_option(port_option, strport.c_str());
    std::string straliases = std::string(web_uri)+std::string("=") + std::string(web_page_dir);
    if (_phttpd->set_option(aliases_option, straliases.c_str()))
        return -1;

    _phttpd->register_uri(web_get_uri, NULL);
    _phttpd->register_uri(web_del_uri, NULL);
    _phttpd->register_uri(web_add_uri, NULL);
    _phttpd->register_uri(web_add_login, NULL);
    _phttpd->register_uri(dev_callback_url, NULL);
    _phttpd->handle_error(404,NULL);//页面请求从这个接口进入，同时也处理相关错误


    return 0;
}

void web_server::release()
{
    _phttpd->fini();
    return ;
}

int web_server::start()
{
    _is_start = true;
    web_pthread::start();
    web_pthread::detach();
    return 0;
}

void web_server::stop()
{
    _is_start = false;
}

void web_server::run()
{
    while (_is_start)
        _phttpd->web_poll(1000);
}

std::string web_server::on_message(std::string struri, std::string strmsg)
{
    if (struri.compare(std::string(web_get_uri))== 0)//查询请求
    {
        return post_get_data(strmsg);
    }
    else if (struri.compare(std::string(web_del_uri))== 0)
    {
        return post_delete_data(strmsg);
    }
    else if (struri.compare(std::string(web_add_uri))== 0)
    {
        return post_add_data(strmsg);
    }
    else if (struri.compare(std::string(web_add_login))== 0)
    {
        return post_login(strmsg);
    }
    return std::string("{\"status\": 404,\"message\":\"没有对应的资源\"}");
}

int web_server::err_message()
{
    return 0;
}


std::string web_server::post_get_data(std::string strpostdata)
{
    int pageno = 1; //默认
    std::string strhid;
    std::string strdevid;
    std::string strtype;
    std::string strpageno;
    std::string strerr = std::string("{\"status\":500,\"message\":\"Parameter error\"}");
    std::stringstream stream(strpostdata);
    ptree pt;
    try{  
        read_json<ptree>(stream, pt);
        strhid = pt.get<std::string>(web_key_hid);
        strdevid = pt.get<std::string>(web_key_devid);
        strtype = pt.get<std::string>(web_key_type);
        strpageno = pt.get<std::string>(web_key_pageNo);
    }catch(ptree_error & e) { 
        return strerr;   
    }

    if (strpageno.length() > 0)
    {
        pageno = boost::lexical_cast<int>(strpageno);
        if (pageno <= 0)
            pageno = 1;
    }
        
    if (strhid.length() != 0)//根据硬件ID查询
    {
        return get_data_by_hid(strhid);
    }
    else if (strdevid.length() != 0)//根据设备ID查询
    {
        return get_data_by_devid(strdevid);
    }
    else if (strtype.length() != 0)
    {
        return get_data_by_type(strtype, pageno);
    }
    else
        return strerr;

}

std::string web_server::post_delete_data(std::string strdata)
{
    std::string strerr = std::string("{\"status\":500,\"message\":\"Parameter error\"}");
    std::stringstream stream(strdata);
    ptree pt;
    try{  
        read_json<ptree>(stream, pt);
        if(pt.count("devid"))  
        {  
            ptree ptChild = pt.get_child("devid");  
            for(BOOST_AUTO(pos, ptChild.begin()); pos != ptChild.end(); ++pos)  
            {  
                std::string strid = pos->second.get_value<std::string>();
                CPagefile::GetInstance().DelDeviceInfoByDid(strid);
            }  
        }  
    }catch(ptree_error & e) { 
        return strerr; 
    }

    return std::string("{\"status\":200,\"message\":\"OK\"}");
}

std::string web_server::post_add_data(std::string strdata)
{
    std::string strerr = std::string("{\"status\":500,\"message\":\"Parameter error\"}");
    std::stringstream stream(strdata);
    ptree pt;
    try{  
        read_json<ptree>(stream, pt);
        if(pt.count("parameter"))  
        {   
            ptree ptArry = pt.get_child("parameter"); 
            BOOST_FOREACH(ptree::value_type &pos, ptArry)   
            {  
                ptree p = pos.second;
                std::string strdid = p.get<std::string>("devid");
                std::string strhid = p.get<std::string>("hid"); 
                std::string strkey = p.get<std::string>("key");  
                CPagefile::GetInstance().AddDeviceInfo(strdid, strhid, strkey);
            }  
        }  
    }catch(ptree_error & e) { 
        return strerr; 
    }

    return std::string("{\"status\":200,\"message\":\"OK\"}");
}

std::string web_server::post_login(std::string strdata)
{
    std::string strerr = std::string("{\"status\":401,\"message\":\"Logon failed\"}");
    std::stringstream stream(strdata);
    ptree pt;
    std::string strname = "";
    std::string strpwd = "";
    try{  
        read_json<ptree>(stream, pt);
        strname = pt.get<std::string>("username");
        strpwd = pt.get<std::string>("password"); //MD5已加密
    }catch(ptree_error & e) { 
        return strerr; 
    }

    int namelen = strname.length();
    int pwdlen = strpwd.length();
    if (namelen <= 0 || namelen > 20 || pwdlen != 32)//帐号和密码最长不超过20个字节
        return strerr;

    boost::property_tree::ptree reader;
    boost::property_tree::ini_parser::read_ini("collectionsvr.ini", reader);
    std::string strininame = reader.get<std::string>("web.WEB_USRNAME");
    std::string strinipwd = reader.get<std::string>("web.WBE_PWD");

    //校验用户名 
    if (strininame.compare(strname) != 0 )
        return std::string("{\"status\":401,\"message\":\"用户名错误\"}");
    
    MD5 md5(strinipwd);
    if (strpwd.compare(md5.hexdigest()) != 0)
        return std::string("{\"status\":401,\"message\":\"密码错误\"}");
    
    return std::string("{\"status\":200,\"message\":\"OK\"}");
}

std::string web_server::get_data_by_hid(std::string strhid)
{
    std::string strdid = "";
    std::string strkey = "";
    CPagefile::GetInstance().GetDeviceInfoByHid(strhid, strdid, strkey);
    std::string strjson = std::string("{\"status\": 200,\"message\":\"OK\",\"response\":{\"pageNo\": 1,\"num\":1, \"pages\":1,\"totals\":1,\"data\":[{\"devid\":\"") 
                            + strdid + std::string("\",\"key\":\"") + strkey + std::string("\",\"hid\":\"") + strhid + std::string("\"}]}}");
    return strjson;
}

std::string web_server::get_data_by_devid(std::string strdevid)
{
    std::string strhid = "";
    std::string strkey = "";
    CPagefile::GetInstance().GetDeviceInfoByDid(strdevid, strhid, strkey);
    std::string strjson = std::string("{\"status\": 200,\"message\":\"OK\",\"response\":{\"pageNo\": 1,\"num\":1, \"pages\":1,\"totals\":1,\"data\":[{\"devid\":\"") 
                            + strdevid + std::string("\",\"key\":\"") + strkey + std::string("\",\"hid\":\"") + strhid
                            + std::string("\"}]}}");
    return strjson;
}

std::string web_server::get_data_by_type(std::string strtype, int pageno)
{
    std::vector<DEVINFO> vecdevinfo;
    vecdevinfo.clear();
    if (strtype.compare(std::string("all")) == 0)
    {
        CPagefile::GetInstance().GetAllDeviceInfo(vecdevinfo);
    }
    else if (strtype.compare(std::string("hidisnull")) == 0)
    {
        CPagefile::GetInstance().GetDeviceInfoOfHidIsNull(vecdevinfo);
    }
    else
    {
        CPagefile::GetInstance().GetDeviceInfoOfHid(vecdevinfo);
    }

    std::string strret = std::string("{\"status\":200,\"message\":\"OK\",\"response\":{\"pageNo\": 0,\"num\":0, \"pages\":0,\"totals\":0,\"data\":\"\"}}");
    int totals = vecdevinfo.size();
    if (totals == 0)
    {
        return strret;
    }

    const int pagenum = 30; //默认每页30条数据
    int beginRow = (pageno-1) * pagenum;
    if (beginRow >= totals )
    {
        return strret;
    }

    int num = totals - beginRow;
    num = (num < pagenum) ? num : pagenum;//每页最多pagenum条
    int pages = (totals + pagenum -1)/pagenum;//总页数

    std::string strjson = boost::str(boost::format("{\"status\":200,\"message\":\"OK\",\"response\":{\"pageNo\":%d,\"num\":%d, \"pages\":%d,\"totals\":%d,\"data\":[") % pageno %num %pages %totals);
    
    int i = beginRow;
    for (; i < beginRow + num; i++)
    {
        strjson += boost::str(boost::format("{\"devid\":\"%s\",\"key\":\"%s\",\"hid\":\"%s\"}")%vecdevinfo[i].strdid %vecdevinfo[i].strkey %vecdevinfo[i].strhid);
        if ((i + 1) < (beginRow + num))
        {
            strjson += std::string(",");  
        }
    }
    strjson += std::string("]}}");
    return strjson;
}

